import store from '@/store'
import dayjs from 'dayjs'
let view
let app = null

function getAppWrap() {
  if (app == null) app = getApp()
  return app
}

function init() {
  const app = getAppWrap()
  app.globalData.debuggerLogData = []
  app.globalData.debuggerNetworkLogData = []
  app.globalData.debuggerErrLogData = []
}

//======================
//调试器使用方法

function addNetworkLog(info, options, data) {
  const app = getAppWrap()
  if (app.globalData.debuggerNetworkLogData.length > 512)
    app.globalData.debuggerNetworkLogData.shift()
  app.globalData.debuggerNetworkLogData.push({ info, options, data })
  uni.$emit('debugger-refresh-network')
}
function addAppErr(err) {
  const app = getAppWrap()
  if (app.globalData.debuggerErrLogData.length > 128) app.globalData.debuggerErrLogData.shift()
  app.globalData.debuggerErrLogData.push({ err: err.toString(), stack: err.stack })
  uni.$emit('debugger-refresh-app-err')
}
function addVueError(err, vm, info) {
  const app = getAppWrap()
  if (app.globalData.debuggerErrLogData.length > 128) app.globalData.debuggerErrLogData.shift()
  app.globalData.debuggerErrLogData.push({ err: err.toString(), stack: err.stack + '\n' + info })
  uni.$emit('debugger-refresh-vue-err')
}
function addLog(info) {
  const app = getAppWrap()
  let removeFirst = false
  if (app.globalData.debuggerLogData.length > 768) {
    app.globalData.debuggerLogData.shift()
    removeFirst = true
  }
  app.globalData.debuggerLogData.push(info)
  uni.$emit('debugger-refresh-log', removeFirst)
}

export const debuggerModule = {
  addNetworkLog,
  addAppErr,
  addVueError,
  addLog
}

//======================
//调试器初始化方法

function pad(num, n) {
  let strNum = num.toString()
  let len = strNum.length
  while (len < n) {
    strNum = '0' + strNum
    len++
  }
  return strNum
}
function getNowTimeString() {
  const d = new Date()
  return pad(d.getHours(), 2) + ':' + pad(d.getMinutes(), 2) + ':' + pad(d.getSeconds(), 2)
}
function installConsoleHook() {
  console.log('installConsoleHook')

  if (debuggerModule) {
    let console_log = console.log
    let console_error = console.error
    let console_info = console.info
    let console_warn = console.warn

    console.log = function (...arg) {
      debuggerModule.addLog({ time: getNowTimeString(), type: 'log', objects: arg })
      console_log(...arg)
    }
    console.error = function (...arg) {
      debuggerModule.addLog({ time: getNowTimeString(), type: 'error', objects: arg })
      console_error(...arg)
    }
    console.info = function (...arg) {
      debuggerModule.addLog({ time: getNowTimeString(), type: 'info', objects: arg })
      console_info(...arg)
    }
    console.warn = function (...arg) {
      debuggerModule.addLog({ time: getNowTimeString(), type: 'warn', objects: arg })
      console_warn(...arg)
    }
  }
}
function getFormat(millisecond) {
  if (millisecond < 1000) {
    return `${millisecond}毫秒`
  } else {
    return `${millisecond/1000}`
  }
}
function installRequestHook() {
  /* 拦截请求 */
  uni.addInterceptor('request', {
    invoke(args) {
      let sendTime = dayjs()
      // request 触发前拼接 url
      const addInterceptorRequestData = {
        data: args.data,
        method: args.method || 'GET',
        sourceUrl: args.url,
        url: args.url,
        status: 0,
        time: ''
      }
      let _complete = args.complete
      args.complete = function (e) {
        _complete && _complete(e)
        let endTime = dayjs()
        addInterceptorRequestData.status = e.statusCode
        addInterceptorRequestData.time = getFormat(
          dayjs(endTime).diff(sendTime, 'millisecond', true)
        )
        addNetworkLog(addInterceptorRequestData, args, e.data)
      }
    }
  })
}

const global = {
  lastTime: 0, //此变量用来记录上次摇动的时间
  intervalTime: 500, // 两次摇一摇的间隔事件
  lastX: 0,
  lastY: 0,
  lastZ: 0, //此组变量分别记录对应x、y、z三轴的数值和上次的数值
  shakeSpeed: 850 //设置阈值
}

function starshake(acceleration) {
  let nowTime = new Date().getTime() //记录当前时间
  //如果这次摇的时间距离上次摇的时间有一定间隔 才执行
  if (nowTime - global.lastTime > 100) {
    let diffTime = nowTime - global.lastTime //记录时间段
    global.lastTime = nowTime // 记录本次摇动时间，为下次计算摇动时间做准备
    let x = acceleration.x // 获取x轴数值，x轴为垂直于北轴，向东为正
    let y = acceleration.y // 获取y轴数值，y轴向正北为正
    let z = acceleration.z // 获取z轴数值，z轴垂直于地面，向上为正

    // 速度计算
    let speed =
      (Math.abs(x + y + z - global.lastX - global.lastY - global.lastZ) / diffTime) * 10000
    //赋值，为下一次计算做准备
    global.lastX = x
    global.lastY = y
    global.lastZ = z
    //如果计算出来的速度超过了阈值，那么就算作用户成功摇一摇
    if (speed > global.shakeSpeed) {
      uni.stopAccelerometer()
      return true
    } else {
      return false
    }
  }
}

/**
 * 获取调试器是否已经安装
 */
export function debuggerEnabled() {
  return getApp().globalData._debuggerEnabled
}
/**
 * 安装调试器
 * @param {type} options 自定义参数
 */
export function installDebugger(options) {
  const app = getAppWrap()
  if (!app.globalData || !app.globalData._debuggerEnabled) {
    init()
    installConsoleHook()
    if (options.enableRequestInterceptor) {
      installRequestHook()
    }
    getApp().globalData._debuggerEnabled = true
  }
}

export function installDebuggerShake() {
  uni.onAccelerometerChange((res) => {
    const shake = starshake(res)
    if (shake) {
      installDebugger({
        enableRequestInterceptor: true,
        showGlobalFloatWindow: true
      })
    }
  })
}
